import { ipcMain, dialog } from 'electron';
import fs from 'fs/promises';
import path from 'path';
import os from 'os';

/**
 * @description 日志级别枚举
 */
const LOG_LEVELS = {
  ERROR: 'ERROR',
  WARN: 'WARN',
  INFO: 'INFO',
  DEBUG: 'DEBUG'
};

/**
 * @description 日志级别优先级（数字越小优先级越高）
 */
const LOG_LEVEL_PRIORITY = {
  ERROR: 0,
  WARN: 1,
  INFO: 2,
  DEBUG: 3
};

/**
 * @description 日志系统配置
 */
const DEFAULT_CONFIG = {
  logDir: path.join(os.homedir(), 'AppData', 'Local', 'MACC', 'logs'), // 默认日志目录
  maxFileSize: 10 * 1024 * 1024, // 最大文件大小 10MB
  maxFiles: 5, // 最大保留文件数量
  logLevel: LOG_LEVELS.INFO, // 默认日志级别
  dateFormat: 'YYYY-MM-DD HH:mm:ss', // 日期格式
  enableConsole: true // 是否同时输出到控制台
};

/**
 * @description 日志管理器类
 */
class Logger {
  constructor(config = {}) {
    this.config = { ...DEFAULT_CONFIG, ...config };
    this.currentLogFile = null;
    this.currentFileSize = 0;
    this.initializeLogDirectory();
  }

  /**
   * @description 初始化日志目录
   */
  async initializeLogDirectory() {
    try {
      await fs.mkdir(this.config.logDir, { recursive: true });
      await this.updateCurrentLogFile();
    } catch (error) {
      console.error('初始化日志目录失败:', error);
    }
  }

  /**
   * @description 更新当前日志文件路径
   */
  async updateCurrentLogFile() {
    const today = this.formatDate(new Date(), 'YYYY-MM-DD');
    this.currentLogFile = path.join(this.config.logDir, `app-${today}.log`);
    
    try {
      const stats = await fs.stat(this.currentLogFile);
      this.currentFileSize = stats.size;
    } catch (error) {
      // 文件不存在，大小为0
      this.currentFileSize = 0;
    }
  }

  /**
   * @description 格式化日期
   * @param {Date} date - 日期对象
   * @param {string} format - 格式字符串
   * @returns {string} - 格式化后的日期字符串
   */
  formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');

    return format
      .replace('YYYY', year)
      .replace('MM', month)
      .replace('DD', day)
      .replace('HH', hours)
      .replace('mm', minutes)
      .replace('ss', seconds);
  }

  /**
   * @description 检查是否应该记录该级别的日志
   * @param {string} level - 日志级别
   * @returns {boolean}
   */
  shouldLog(level) {
    return LOG_LEVEL_PRIORITY[level] <= LOG_LEVEL_PRIORITY[this.config.logLevel];
  }

  /**
   * @description 格式化日志消息
   * @param {string} level - 日志级别
   * @param {string} message - 日志消息
   * @param {object} meta - 额外的元数据
   * @returns {string} - 格式化后的日志字符串
   */
  formatLogMessage(level, message, meta = {}) {
    const timestamp = this.formatDate(new Date(), this.config.dateFormat);
    const category = meta.category || 'system'; // 默认分类为 system
    const details = Object.keys(meta).length > 0 ? JSON.stringify(meta) : '';
    return `[${timestamp}] [${level}] [${category}] ${message}${details ? ' | ' + details : ''}\n`;
  }

  /**
   * @description 检查并执行日志文件轮转
   */
  async rotateLogFileIfNeeded() {
    if (this.currentFileSize >= this.config.maxFileSize) {
      await this.rotateLogFile();
    }
  }

  /**
   * @description 执行日志文件轮转
   */
  async rotateLogFile() {
    try {
      const today = this.formatDate(new Date(), 'YYYY-MM-DD');
      const timestamp = this.formatDate(new Date(), 'YYYY-MM-DD-HHmmss');
      const rotatedFileName = `app-${today}-${timestamp}.log`;
      const rotatedFilePath = path.join(this.config.logDir, rotatedFileName);

      // 重命名当前日志文件
      if (this.currentLogFile && await this.fileExists(this.currentLogFile)) {
        await fs.rename(this.currentLogFile, rotatedFilePath);
      }

      // 重置当前文件大小
      this.currentFileSize = 0;

      // 清理旧日志文件
      await this.cleanOldLogFiles();
    } catch (error) {
      console.error('日志文件轮转失败:', error);
    }
  }

  /**
   * @description 清理旧的日志文件
   */
  async cleanOldLogFiles() {
    try {
      const files = await fs.readdir(this.config.logDir);
      const logFiles = files
        .filter(file => file.endsWith('.log'))
        .map(file => ({
          name: file,
          path: path.join(this.config.logDir, file),
          time: fs.stat(path.join(this.config.logDir, file)).then(stats => stats.mtime)
        }));

      // 等待所有文件状态获取完成
      for (let file of logFiles) {
        file.time = await file.time;
      }

      // 按修改时间排序，保留最新的文件
      logFiles.sort((a, b) => b.time - a.time);

      // 删除超出数量限制的文件
      if (logFiles.length > this.config.maxFiles) {
        const filesToDelete = logFiles.slice(this.config.maxFiles);
        for (let file of filesToDelete) {
          await fs.unlink(file.path);
          console.log(`已删除旧日志文件: ${file.name}`);
        }
      }
    } catch (error) {
      console.error('清理旧日志文件失败:', error);
    }
  }

  /**
   * @description 检查文件是否存在
   * @param {string} filePath - 文件路径
   * @returns {Promise<boolean>}
   */
  async fileExists(filePath) {
    try {
      await fs.access(filePath);
      return true;
    } catch {
      return false;
    }
  }

  /**
   * @description 写入日志
   * @param {string} level - 日志级别
   * @param {string} message - 日志消息
   * @param {object} meta - 额外的元数据
   */
  async writeLog(level, message, meta = {}) {
    if (!this.shouldLog(level)) {
      return;
    }

    const logMessage = this.formatLogMessage(level, message, meta);

    // 输出到控制台
    if (this.config.enableConsole) {
      const consoleMethod = level === 'ERROR' ? 'error' : 
                           level === 'WARN' ? 'warn' : 
                           level === 'DEBUG' ? 'debug' : 'log';
      console[consoleMethod](`[${level}] ${message}`, meta);
    }

    try {
      // 确保当前日志文件是最新的
      await this.updateCurrentLogFile();

      // 检查是否需要轮转
      await this.rotateLogFileIfNeeded();

      // 写入文件
      await fs.appendFile(this.currentLogFile, logMessage, 'utf8');
      this.currentFileSize += Buffer.byteLength(logMessage, 'utf8');
    } catch (error) {
      console.error('写入日志文件失败:', error);
    }
  }

  /**
   * @description 记录错误日志
   * @param {string} message - 日志消息
   * @param {object} meta - 额外的元数据
   */
  async error(message, meta = {}) {
    await this.writeLog(LOG_LEVELS.ERROR, message, meta);
  }

  /**
   * @description 记录警告日志
   * @param {string} message - 日志消息
   * @param {object} meta - 额外的元数据
   */
  async warn(message, meta = {}) {
    await this.writeLog(LOG_LEVELS.WARN, message, meta);
  }

  /**
   * @description 记录信息日志
   * @param {string} message - 日志消息
   * @param {object} meta - 额外的元数据
   */
  async info(message, meta = {}) {
    await this.writeLog(LOG_LEVELS.INFO, message, meta);
  }

  /**
   * @description 记录调试日志
   * @param {string} message - 日志消息
   * @param {object} meta - 额外的元数据
   */
  async debug(message, meta = {}) {
    await this.writeLog(LOG_LEVELS.DEBUG, message, meta);
  }

  /**
   * @description 获取日志文件列表
   * @returns {Promise<Array>} - 日志文件信息数组
   */
  async getLogFiles() {
    try {
      const files = await fs.readdir(this.config.logDir);
      const logFiles = [];

      for (let file of files) {
        if (file.endsWith('.log')) {
          const filePath = path.join(this.config.logDir, file);
          const stats = await fs.stat(filePath);
          logFiles.push({
            name: file,
            path: filePath,
            size: stats.size,
            modified: stats.mtime,
            created: stats.birthtime
          });
        }
      }

      return logFiles.sort((a, b) => b.modified - a.modified);
    } catch (error) {
      console.error('获取日志文件列表失败:', error);
      return [];
    }
  }

  /**
   * @description 读取日志文件内容
   * @param {string} fileName - 文件名
   * @param {number} lines - 读取的行数（从末尾开始）
   * @returns {Promise<string>} - 日志内容
   */
  async readLogFile(fileName, lines = 100) {
    try {
      const filePath = path.join(this.config.logDir, fileName);
      const content = await fs.readFile(filePath, 'utf8');
      
      if (lines > 0) {
        const allLines = content.split('\n');
        const selectedLines = allLines.slice(-lines);
        return selectedLines.join('\n');
      }
      
      return content;
    } catch (error) {
      console.error('读取日志文件失败:', error);
      throw new Error(`读取日志文件失败: ${error.message}`);
    }
  }

  /**
   * @description 清空所有日志文件
   */
  async clearAllLogs() {
    try {
      const files = await fs.readdir(this.config.logDir);
      for (let file of files) {
        if (file.endsWith('.log')) {
          await fs.unlink(path.join(this.config.logDir, file));
        }
      }
      this.currentFileSize = 0;
      console.log('所有日志文件已清空');
    } catch (error) {
      console.error('清空日志文件失败:', error);
      throw new Error(`清空日志文件失败: ${error.message}`);
    }
  }
}

// 创建全局日志实例
const logger = new Logger();

/**
 * @description 注册日志相关的 IPC 处理函数
 */
function handleLogger() {
  /**
   * 处理渲染进程发起的写入日志请求
   * @param {Electron.IpcMainInvokeEvent} event - IPC 事件对象
   * @param {string} level - 日志级别
   * @param {string} message - 日志消息
   * @param {object} meta - 额外的元数据
   * @returns {Promise<{success: boolean, error?: string}>}
   */
  ipcMain.handle('logger:write', async (event, level, message, meta = {}) => {
    try {
      await logger.writeLog(level, message, meta);
      return { success: true };
    } catch (error) {
      return { success: false, error: error.message };
    }
  });

  /**
   * 处理渲染进程发起的获取日志文件列表请求
   * @param {Electron.IpcMainInvokeEvent} event - IPC 事件对象
   * @returns {Promise<{success: boolean, data?: Array, error?: string}>}
   */
  ipcMain.handle('logger:getFiles', async (event) => {
    try {
      const files = await logger.getLogFiles();
      return { success: true, data: files };
    } catch (error) {
      return { success: false, error: error.message };
    }
  });

  /**
   * 处理渲染进程发起的读取日志文件请求
   * @param {Electron.IpcMainInvokeEvent} event - IPC 事件对象
   * @param {string} fileName - 文件名
   * @param {number} lines - 读取的行数
   * @returns {Promise<{success: boolean, data?: string, error?: string}>}
   */
  ipcMain.handle('logger:readFile', async (event, fileName, lines = 100) => {
    try {
      const content = await logger.readLogFile(fileName, lines);
      return { success: true, data: content };
    } catch (error) {
      return { success: false, error: error.message };
    }
  });

  /**
   * 处理渲染进程发起的清空日志请求
   * @param {Electron.IpcMainInvokeEvent} event - IPC 事件对象
   * @returns {Promise<{success: boolean, error?: string}>}
   */
  ipcMain.handle('logger:clear', async (event) => {
    try {
      await logger.clearAllLogs();
      return { success: true };
    } catch (error) {
      return { success: false, error: error.message };
    }
  });

  /**
   * 处理渲染进程发起的获取日志配置请求
   * @param {Electron.IpcMainInvokeEvent} event - IPC 事件对象
   * @returns {Promise<{success: boolean, data?: object, error?: string}>}
   */
  ipcMain.handle('logger:getConfig', async (event) => {
    try {
      return { success: true, data: logger.config };
    } catch (error) {
      return { success: false, error: error.message };
    }
  });

  /**
   * 处理渲染进程发起的更新日志配置请求
   * @param {Electron.IpcMainInvokeEvent} event - IPC 事件对象
   * @param {object} newConfig - 新的配置对象
   * @returns {Promise<{success: boolean, error?: string}>}
   */
  ipcMain.handle('logger:updateConfig', async (event, newConfig) => {
    try {
      logger.config = { ...logger.config, ...newConfig };
      await logger.initializeLogDirectory();
      return { success: true };
    } catch (error) {
      return { success: false, error: error.message };
    }
  });

  /**
   * 处理渲染进程发起的获取解析后日志数据请求
   * @param {Electron.IpcMainInvokeEvent} event - IPC 事件对象
   * @returns {Promise<{success: boolean, logs?: Array, error?: string}>}
   */
  ipcMain.handle('logger:getParsedLogs', async (event) => {
    try {
      // 获取日志文件列表
      const files = await logger.getLogFiles();
      if (!files || files.length === 0) {
        return { success: true, logs: [] };
      }
      
      // 获取最新的日志文件
      const latestFile = files[0]; // 文件列表已按时间排序
      const content = await logger.readLogFile(latestFile.name, 1000);
      
      if (!content) {
        return { success: true, logs: [] };
      }
      
      // 解析日志内容为结构化数据
      const logs = parseLogContent(content);
      return { success: true, logs };
    } catch (error) {
      return { success: false, error: error.message, logs: [] };
    }
  });

  /**
   * 处理渲染进程发起的导出日志请求
   * @param {Electron.IpcMainInvokeEvent} event - IPC 事件对象
   * @param {Array} logs - 要导出的日志数据
   * @param {string} filePath - 导出文件路径
   * @returns {Promise<{success: boolean, error?: string}>}
   */
  ipcMain.handle('logger:exportToCSV', async (event, logs, filePath) => {
    try {
      if (!logs || logs.length === 0) {
        throw new Error('没有可导出的日志数据');
      }
      
      // 转换为 CSV 格式
      const csvContent = convertLogsToCSV(logs);
      
      // 写入文件
      await fs.writeFile(filePath, csvContent, 'utf8');
      
      return { success: true };
    } catch (error) {
      return { success: false, error: error.message };
    }
  });

  /**
   * 处理渲染进程发起的完整导出日志请求（包含文件对话框）
   * @param {Electron.IpcMainInvokeEvent} event - IPC 事件对象
   * @param {Array} logs - 要导出的日志数据
   * @returns {Promise<{success: boolean, filePath?: string, error?: string}>}
   */
  ipcMain.handle('logger:exportLogsWithDialog', async (event, logs) => {
    try {
      if (!logs || logs.length === 0) {
        throw new Error('没有可导出的日志数据');
      }
      
      // 显示保存对话框
      const result = await dialog.showSaveDialog({
        title: '导出日志',
        defaultPath: `logs_${new Date().toISOString().slice(0, 10)}.csv`,
        filters: [
          { name: 'CSV 文件', extensions: ['csv'] },
          { name: '所有文件', extensions: ['*'] }
        ]
      });
      
      if (result.canceled) {
        return { success: false, error: '用户取消了导出操作' };
      }
      
      // 转换为 CSV 格式
      const csvContent = convertLogsToCSV(logs);
      
      // 写入文件
      await fs.writeFile(result.filePath, csvContent, 'utf8');
      
      // 记录导出操作
      await logger.writeLog('INFO', '日志导出成功', {
        category: 'user',
        action: 'export_logs',
        filePath: result.filePath,
        recordCount: logs.length
      });
      
      return { success: true, filePath: result.filePath };
    } catch (error) {
      // 记录错误
      await logger.writeLog('ERROR', '日志导出失败', {
        category: 'system',
        error: error.message
      });
      
      return { success: false, error: error.message };
    }
  });

  /**
   * 处理渲染进程发起的清空日志请求（包含日志记录）
   * @param {Electron.IpcMainInvokeEvent} event - IPC 事件对象
   * @returns {Promise<{success: boolean, error?: string}>}
   */
  ipcMain.handle('logger:clearLogsWithLogging', async (event) => {
    try {
      // 先记录清空操作
      await logger.writeLog('INFO', '日志清空操作', {
        category: 'user',
        action: 'clear_logs'
      });
      
      // 执行清空操作
      await logger.clearAllLogs();
      
      return { success: true };
    } catch (error) {
      // 记录错误
      await logger.writeLog('ERROR', '清空日志失败', {
        category: 'system',
        error: error.message
      });
      
      return { success: false, error: error.message };
    }
  });
}

/**
 * 解析日志文件内容为结构化数据
 * @param {string} content - 日志文件内容
 * @returns {Array} 解析后的日志数组
 */
function parseLogContent(content) {
  if (!content) return [];
  
  const lines = content.split('\n').filter(line => line.trim());
  const logs = [];
  
  lines.forEach((line, index) => {
    try {
      // 日志格式: [2024-01-01 12:00:00] [INFO] [category] message | details
      const logRegex = /^\[([^\]]+)\]\s*\[([^\]]+)\]\s*\[([^\]]+)\]\s*([^|]+)(?:\s*\|\s*(.+))?$/;
      const match = line.match(logRegex);
      
      if (match) {
        const [, timestamp, level, category, message, details] = match;
        logs.push({
          id: `log_${Date.now()}_${index}`,
          timestamp: timestamp.trim(),
          level: level.trim(),
          category: category.trim(),
          message: message.trim(),
          details: details ? details.trim() : null
        });
      }
    } catch (error) {
      console.warn('解析日志行失败:', line, error);
    }
  });
  
  return logs;
}

/**
 * 将日志数据转换为 CSV 格式
 * @param {Array} logs - 日志数组
 * @returns {string} CSV 格式的字符串
 */
function convertLogsToCSV(logs) {
  if (!logs || logs.length === 0) return '';
  
  // CSV 头部
  const headers = ['时间戳', '级别', '分类', '消息', '详细信息'];
  let csv = headers.join(',') + '\n';
  
  // 数据行
  logs.forEach(log => {
    const row = [
      `"${log.timestamp || log.时间 || ''}"`,
      `"${log.level || log.级别 || ''}"`,
      `"${log.category || log.分类 || ''}"`,
      `"${(log.message || log.消息 || '').replace(/"/g, '""')}"`,  // 转义双引号
      `"${(log.details || log.详情 || '').replace(/"/g, '""')}"` // 详细信息，可能为空
    ];
    csv += row.join(',') + '\n';
  });
  
  return csv;
}

// 导出日志实例和处理函数
export { logger, handleLogger, LOG_LEVELS };